repo: Fix race condition in async checkout
authorColin Walters <walters@verbum.org>
Tue, 30 Apr 2013 23:34:20 +0000 (19:34 -0400)
committerColin Walters <walters@verbum.org>
Tue, 30 Apr 2013 23:34:20 +0000 (19:34 -0400)
When multiple threads need to uncompress an object, there was
a race condition where thread A could get EEXIST, unlink,
then thread B calls linkat(), then thread A tries to link() but
fails.

We can just loop in this case.

src/libostree/ostree-repo.c

index e793875b361940fbc6f50c2b9035873ba79ac16e..f4ad8fe4f41a96787eb3155e714a3d50b014779f 100644 (file)
@@ -3194,6 +3194,7 @@ checkout_file_hardlink (OstreeRepo                  *self,
   gboolean ret_was_supported = FALSE;
   ot_lobj GFile *dir = NULL;
 
+ again:
   if (dirfd != -1 &&
       linkat (-1, gs_file_get_path_cached (source),
               dirfd, gs_file_get_basename_cached (destination), 0) != -1)
@@ -3218,11 +3219,7 @@ checkout_file_hardlink (OstreeRepo                  *self,
        * So we can't make this atomic.  
        */
       (void) unlink (gs_file_get_path_cached (destination));
-      if (link (gs_file_get_path_cached (source), gs_file_get_path_cached (destination)) < 0)
-        {
-          ot_util_set_error_from_errno (error, errno);
-          goto out;
-        }
+      goto again;
       ret_was_supported = TRUE;
     }
   else